import cv2
import numpy as np
from Sudoku.TwoArray import TwoArray


class Coordinate:
    def __init__(self):
        """
        初始化 SudokuExtractor 类。
        """
        pass

    def preprocess_image(self, img):
        """
        图像预处理：灰度化和二值化。
        :param img: 输入的彩色图像
        :return: 二值化后的图像
        """
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度化
        thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                       cv2.THRESH_BINARY_INV, 11, 2)  # 二值化
        return thresh

    def extract_largest_contour(self, img):
        """
        提取图像中的最大轮廓。
        :param img: 二值化后的图像
        :return: 最大轮廓和掩码图像
        """
        contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        largest = max(contours, key=cv2.contourArea)  # 找到最大轮廓
        mask = np.zeros_like(img)
        cv2.drawContours(mask, [largest], -1, 255, thickness=cv2.FILLED)  # 绘制最大轮廓
        return largest, mask

    def draw_green_bounding_box(self, img, contour):
        """
        在图像上绘制绿色外框。
        :param img: 原始图像
        :param contour: 最大轮廓
        :return: 绘制绿色外框后的图像和外接矩形坐标 (x, y, w, h)
        """
        # 获取轮廓的外接矩形
        x, y, w, h = cv2.boundingRect(contour)
        # 在图像上绘制绿色矩形框
        img_with_box = img.copy()
        cv2.rectangle(img_with_box, (x, y), (x + w, y + h), (0, 255, 0), 2)
        return img_with_box, (x, y, w, h)

    def divide_into_grid(self, img, x, y, w, h, grid_size=(9, 9)):
        """
        将外框内的区域平均分为 9x9 网格，并计算每个小图的中心点坐标。
        :param img: 原始图像
        :param x, y, w, h: 外接矩形的坐标和宽高
        :param grid_size: 网格大小 (默认 9x9)
        :return: 图像和中心点坐标列表
        """
        # 计算每个小格的宽度和高度
        cell_width = w // grid_size[0]
        cell_height = h // grid_size[1]

        # 存储中心点坐标
        center_points = []

        # 遍历每个小格
        for i in range(grid_size[0]):
            for j in range(grid_size[1]):
                # 计算当前小格的中心点坐标
                center_x = x + (i * cell_width) + (cell_width // 2)
                center_y = y + (j * cell_height) + (cell_height // 2)
                center_points.append((center_x, center_y))

                # 在中心点绘制 10x10 像素的红点
                cv2.rectangle(img, (center_x - 5, center_y - 5), (center_x + 5, center_y + 5), (0, 0, 255), -1)
        return img, center_points

    def draw_blue_points(self, img, center_points, x, y, w, h):
        """
        在绿色框下沿和图像底部的中间位置绘制 9 个蓝点。
        蓝点的横坐标为最后 9 个红点的横坐标，纵坐标为绿框下沿到图像底部距离的一半。
        :param img: 原始图像
        :param center_points: 81 个中心点坐标
        :param x, y, w, h: 外接矩形的坐标和宽高
        :return: 绘制蓝点后的图像和蓝点坐标
        """
        # 计算绿框下沿到图像底部的距离，并除以 2 得到纵轴坐标
        vertical_axis = y + h + (img.shape[0] - (y + h)) // 2
        # print(f"绿框下沿到图像底部的距离的一半 (纵轴坐标): {vertical_axis}")
        # 获取最后 9 个红点的坐标
        last_nine_points = TwoArray.reshape_to_2d_grid(center_points)
        last_nine_points = last_nine_points[-1]
        # print(center_points)
        # print("最后 9 个红点的坐标:", last_nine_points)

        # 存储蓝点坐标
        blue_points = []

        # 遍历最后 9 个红点
        for idx, (red_x, red_y) in enumerate(last_nine_points):
            # 蓝点的坐标为 (red_x, vertical_axis)
            blue_x = red_x
            blue_y = vertical_axis
            blue_points.append((blue_x, blue_y))
            # 绘制 10x10 像素的蓝点
            cv2.rectangle(img, (blue_x - 5, blue_y - 5), (blue_x + 5, blue_y + 5), (255, 0, 0), -1)
        # print("蓝点坐标：", blue_points)
        return img, blue_points

    def process_image(self, image_path):
        """
        处理图像：提取最大轮廓并标记绿色外框，分割网格，绘制中心点，绘制蓝点并标记编号。
        :param image_path: 图像文件路径
        """
        # 读取图像
        img = cv2.imread(image_path)
        if img is None:
            raise ValueError("无法加载图像，请检查路径是否正确。")

        # 获取图像的长宽
        height, width = img.shape[:2]
        print(f"图像尺寸：{width}x{height}，点击位置不对时，需要修改模拟器分辨率：{width}x{height}")

        # 图像预处理
        processed = self.preprocess_image(img)

        # 提取最大轮廓
        largest_contour, _ = self.extract_largest_contour(processed)

        # 在图像上绘制绿色外框，并获取外接矩形坐标
        img_with_box, (x, y, w, h) = self.draw_green_bounding_box(img, largest_contour)

        # 将外框内的区域分为 9x9 网格，并绘制中心点
        img_with_grid, center_points = self.divide_into_grid(img_with_box, x, y, w, h)
        center_points_2 = TwoArray.reshape_to_2d_grid(center_points)

        # print("81个红色坐标:", center_points_2)  # 打印红色坐标

        # 在绿色框下沿和图像底部的中间位置绘制 9 个蓝点
        img_with_blue_points, blue_points = self.draw_blue_points(img_with_grid, center_points, x, y, w, h)
        # print("9个蓝色坐标:", blue_points)  # 打印蓝点坐标
        return (center_points_2, blue_points)
        # 显示红色和蓝色
        # cv2.imshow("Sudoku with Grid, Red Points, and Blue Points", img_with_blue_points)
        # cv2.waitKey(0)  # 等待按键
        # cv2.destroyAllWindows()  # 关闭窗口


# 示例用法
if __name__ == '__main__':
    # 初始化 SudokuExtractor
    """
    获取九宫格坐标点
    获取123456789坐标点
    """
    extractor = Coordinate()

    # 处理图像
    image_path = "../Sudoku/png.jpg"  # 替换为你的图像路径
    try:
        extractor.process_image(image_path)
    except Exception as e:
        print("发生错误：", str(e))
